1
/****************************** Module Header ******************************\
2 * Module Name: FTPDownloadClient.cs
3 * Project: CSFTPDownload
4 * Copyright (c) Microsoft Corporation.
6 * This class is used to download files from a FTP server. When the download
7 * starts, it will download the file in a background thread. The downloaded
8 * data is stored in a MemoryStream first, and then written to local file.
11 * This source is subject to the Microsoft Public License.
12 * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
13 * All other rights reserved.
15 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
16 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
18 \***************************************************************************/
21 using System
.Collections
.Generic
;
24 using System
.Threading
;
26 namespace CSFTPDownload
28 public partial class FTPClientManager
31 public class FTPDownloadClient
34 public const int MaxCacheSize
= 2097152;
37 public const int BufferSize
= 2048;
39 FTPClientManager manager
;
41 public event EventHandler
<FileDownloadCompletedEventArgs
>
42 FileDownloadCompleted
;
44 public event EventHandler AllFilesDownloadCompleted
;
46 public FTPDownloadClient(FTPClientManager manager
)
50 throw new ArgumentNullException("FTPClientManager cannot be null.");
53 this.manager
= manager
;
57 /// Download files, directories and their subdirectories.
59 public void DownloadDirectoriesAndFiles(IEnumerable
<FTPFileSystem
> files
,
64 throw new ArgumentNullException(
65 "The files to download cannot be null.");
68 // Create a thread to download data.
69 ParameterizedThreadStart threadStart
=
70 new ParameterizedThreadStart(StartDownloadDirectoriesAndFiles
);
71 Thread downloadThread
= new Thread(threadStart
);
72 downloadThread
.IsBackground
= true;
73 downloadThread
.Start(new object[] { files, localPath }
);
77 /// Download files, directories and their subdirectories.
79 void StartDownloadDirectoriesAndFiles(object state
)
81 var paras
= state
as object[];
83 IEnumerable
<FTPFileSystem
> files
= paras
[0] as IEnumerable
<FTPFileSystem
>;
84 string localPath
= paras
[1] as string;
86 foreach (var file
in files
)
88 DownloadDirectoryOrFile(file
, localPath
);
91 this.OnAllFilesDownloadCompleted(EventArgs
.Empty
);
95 /// Download a single file or directory.
97 void DownloadDirectoryOrFile(FTPFileSystem fileSystem
, string localPath
)
100 // Download the file directly.
101 if (!fileSystem
.IsDirectory
)
103 DownloadFile(fileSystem
, localPath
);
106 // Download a directory.
110 // Construct the directory Path.
111 string directoryPath
= localPath
+ "\\" + fileSystem
.Name
;
113 if (!Directory
.Exists(directoryPath
))
115 Directory
.CreateDirectory(directoryPath
);
118 // Get the sub directories and files.
119 var subDirectoriesAndFiles
=
120 this.manager
.GetSubDirectoriesAndFiles(fileSystem
.Url
);
122 // Download the files in the folder and sub directories.
123 foreach (var subFile
in subDirectoriesAndFiles
)
125 DownloadDirectoryOrFile(subFile
, directoryPath
);
131 /// Download a single file directly.
133 void DownloadFile(FTPFileSystem file
, string localPath
)
135 if (file
.IsDirectory
)
137 throw new ArgumentException(
138 "The FTPFileSystem to download is a directory in fact");
141 string destPath
= localPath
+ "\\" + file
.Name
;
143 // Create a request to the file to be downloaded.
144 FtpWebRequest request
= WebRequest
.Create(file
.Url
) as FtpWebRequest
;
146 request
.Credentials
= this.manager
.Credentials
;
149 request
.Method
= WebRequestMethods
.Ftp
.DownloadFile
;
151 FtpWebResponse response
= null;
152 Stream responseStream
= null;
153 MemoryStream downloadCache
= null;
159 // Retrieve the response from the server and get the response stream.
160 response
= request
.GetResponse() as FtpWebResponse
;
162 this.manager
.OnNewMessageArrived(new NewMessageEventArg
164 NewMessage
= response
.StatusDescription
167 responseStream
= response
.GetResponseStream();
169 // Cache data in memory.
170 downloadCache
= new MemoryStream(FTPDownloadClient
.MaxCacheSize
);
171 byte[] downloadBuffer
= new byte[FTPDownloadClient
.BufferSize
];
176 // Download the file until the download is completed.
180 // Read a buffer of data from the stream.
181 bytesSize
= responseStream
.Read(downloadBuffer
, 0,
182 downloadBuffer
.Length
);
184 // If the cache is full, or the download is completed, write
185 // the data in cache to local file.
187 || MaxCacheSize
< cachedSize
+ bytesSize
)
191 // Write the data in cache to local file.
192 WriteCacheToFile(downloadCache
, destPath
, cachedSize
);
194 // Stop downloading the file if the download is paused,
195 // canceled or completed.
202 downloadCache
.Seek(0, SeekOrigin
.Begin
);
207 string msg
= string.Format(
208 "There is an error while downloading {0}. "
209 + " See InnerException for detailed error. ",
211 ApplicationException errorException
212 = new ApplicationException(msg
, ex
);
214 // Fire the DownloadCompleted event with the error.
215 ErrorEventArgs e
= new ErrorEventArgs
217 ErrorException
= errorException
220 this.manager
.OnErrorOccurred(e
);
227 // Write the data from the buffer to the cache in memory.
228 downloadCache
.Write(downloadBuffer
, 0, bytesSize
);
229 cachedSize
+= bytesSize
;
232 var fileDownloadCompletedEventArgs
= new FileDownloadCompletedEventArgs
235 LocalFile
= new FileInfo(destPath
),
236 ServerPath
= file
.Url
239 this.OnFileDownloadCompleted(fileDownloadCompletedEventArgs
);
243 if (response
!= null)
248 if (responseStream
!= null)
250 responseStream
.Close();
253 if (downloadCache
!= null)
255 downloadCache
.Close();
261 /// Write the data in cache to local file.
263 void WriteCacheToFile(MemoryStream downloadCache
, string downloadPath
,
266 using (FileStream fileStream
= new FileStream(downloadPath
,
269 byte[] cacheContent
= new byte[cachedSize
];
270 downloadCache
.Seek(0, SeekOrigin
.Begin
);
271 downloadCache
.Read(cacheContent
, 0, cachedSize
);
272 fileStream
.Write(cacheContent
, 0, cachedSize
);
276 protected virtual void OnFileDownloadCompleted(FileDownloadCompletedEventArgs e
)
279 if (FileDownloadCompleted
!= null)
281 FileDownloadCompleted(this, e
);
285 protected virtual void OnAllFilesDownloadCompleted(EventArgs e
)
287 if (AllFilesDownloadCompleted
!= null)
289 AllFilesDownloadCompleted(this, e
);